package com.zhouxl.program.multi.seckill;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * @author zhouxl
 * @DATE 2021/7/12
 * @descriptoin
 */
@Component
public class SeckillService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private JedisPool jedisPool;

    private Logger logger = LoggerFactory.getLogger(this.getClass().getName());

    /**
     * 秒杀活动进行逻辑
     * @return
     */
    public Object seckillProduct(String productId) {
        String userId = new Random().nextInt(2000)+"";
        doSeckillSellMoreByJedis(productId,userId);
        return "";
    }

    /**
     * 通过lua脚本进行解决 - 超卖问题
     * @param productId
     * @param userId
     * @return
     */
    private boolean doSeckillByLua(String productId,String userId){
        boolean isSuccess = false;
        // 1.数据校验，校验productId和userId是否为空
        if ( productId == null || userId == null ){
            logger.info("参数异常");
            isSuccess = false;
            return isSuccess;
        }
        // 2.判断redisTemplate对象是否为空
        Jedis jedis = jedisPool.getResource();
        if( jedis == null ){
            logger.info("服务器异常-(redis)");
            jedis.close();
            isSuccess = false;
            return isSuccess;
        }
        // 3.家在执行的lua脚本，处理秒杀活动的业务逻辑
        try{
            String scriptLoad = jedis.scriptLoad(SeckillLua.getSeckillScripts());
            Object resultObj = jedis.evalsha(scriptLoad, 2, userId, productId);
            String result = String.valueOf(resultObj);
            if( SeckillLua.SECKILL_NO_START.equals(result) ){
                logger.info("秒杀活动(当前已经参与秒杀活动了,不能再参加了)");
                isSuccess = false;
            }else if( SeckillLua.SECKILL_SUCCESS.equals(result)){
                logger.info("秒杀活动(秒杀成功)");
                isSuccess = true;
            }else if( SeckillLua.SECKILL_EXCEPTION.equals(result) ){
                logger.info("秒杀活动(秒杀活动已经结束)");
                isSuccess = false;
            }else {
                isSuccess = false;
            }
        }catch (Exception ex){
            isSuccess = false;
        }finally {
            jedis.close();
        }
        return isSuccess;
    }

    /**
     * 秒杀活动的业务逻辑 - 处理超卖逻辑
     * watch + multi + exec
     * @param productId
     * @param userId
     * @return
     */
    private boolean doSeckillSellMoreByJedis(String productId,String userId){
        // 1.数据校验，校验productId和userId是否为空
        if ( productId == null || userId == null ){
            logger.info("参数异常");
            return false;
        }
        // 2.判断redisTemplate对象是否为空
        Jedis jedis = jedisPool.getResource();
        if( jedis == null ){
            logger.info("服务器异常-(redis)");
            jedis.close();
            return false;
        }
        //  3.获取秒杀活动的key
        //  3.1.商品的key
        //  3.2.秒杀活动用户的key
        String productRedisKey = "sk:" + productId + ":prod";
        String userRedisKey = "sk:" + productId + ":user";

        // 4.判断当前活动是否开始了
        jedis.watch(productRedisKey);
        if( !jedis.exists(productRedisKey) ){
            logger.info("当前活动并未开始");
            jedis.close();
            return false;
        }

        // 5.判断当前是否参加了秒杀了

        if( jedis.sismember(userRedisKey,userId) ){
            logger.info("当前用户已经参加了秒杀活动了");
            jedis.close();
            return false;
        }

        // 6.如果商品数量 <1了那么，秒杀活动结束了
        int productNum = Integer.parseInt(jedis.get(productRedisKey));
        if( productNum <= 0 ){
            logger.info("秒杀活动已经结束了");
            jedis.close();
            return false;
        }

        // 7.秒杀活动逻辑
        Transaction multi = jedis.multi();
        List<Object> result = new ArrayList<>();
        try{
            multi.decr(productRedisKey);
            multi.sadd(userRedisKey,userId);
            result = multi.exec();
        }catch (Exception ex){
            multi.discard();
        }finally {
            jedis.close();
        }
        if( result == null || result.size() == 0 ){
            logger.info("秒杀失败");
            return false;
        }
        logger.info("秒杀成功");
        return true;
    }


    /**
     * 秒杀活动的业务逻辑 - 处理超卖逻辑
     * watch + multi + exec
     * @param productId
     * @param userId
     * @return
     */
    private boolean doSeckillSellMore(String productId,String userId){
        // 1.数据校验，校验productId和userId是否为空
        if ( productId == null || userId == null ){
            logger.info("参数异常");
            return false;
        }
        // 2.判断redisTemplate对象是否为空
        if( redisTemplate == null ){
            logger.info("服务器异常-(redis)");
            return false;
        }
        //  3.获取秒杀活动的key
        //  3.1.商品的key
        //  3.2.秒杀活动用户的key
        String productRedisKey = "sk:" + productId + ":prod";
        String userRedisKey = "sk:" + productId + ":user";

        // 4.判断当前活动是否开始了
        redisTemplate.watch(productRedisKey);
        if( !redisTemplate.hasKey(productRedisKey) ){
            logger.info("当前活动并未开始");
            return false;
        }

        // 5.判断当前是否参加了秒杀了
        if( redisTemplate.opsForSet().isMember(userRedisKey,userId) ){
            logger.info("当前用户已经参加了秒杀活动了");
            return false;
        }

        // 6.如果商品数量 <1了那么，秒杀活动结束了
        int productNum = Integer.parseInt((String)redisTemplate.opsForValue().get(productRedisKey));
        if( productNum <= 0 ){
            logger.info("秒杀活动已经结束了");
            redisTemplate.exec();
            return false;
        }
        // 7.秒杀活动逻辑
        redisTemplate.setEnableTransactionSupport(true);
        redisTemplate.multi();
        List<Object> result = new ArrayList<>();
        try{
            redisTemplate.opsForValue().decrement(productRedisKey);
            redisTemplate.opsForSet().add(userRedisKey,userId);
            result = redisTemplate.exec();
        }catch (Exception ex){
            redisTemplate.discard();
        }

        if( result == null || result.size() == 0 ){
            logger.info("秒杀失败");
            return false;
        }
        logger.info("秒杀成功");
        return true;
    }



    /**
     * 秒杀活动的业务逻辑
     * 当前逻辑存在超卖问题
     * @param productId
     * @param userId
     * @return
     */
    private boolean doSeckill(String productId,String userId){
        // 1.数据校验，校验productId和userId是否为空
        if ( productId == null || userId == null ){
            logger.info("参数异常");
            return false;
        }
        // 2.判断redisTemplate对象是否为空
        if( redisTemplate == null ){
            logger.info("服务器异常-(redis)");
            return false;
        }
        //  3.获取秒杀活动的key
        //  3.1.商品的key
        //  3.2.秒杀活动用户的key
        String productRedisKey = "sk:" + productId + ":prod";
        String userRedisKey = "sk:" + productId + ":user";

        // 4.判断当前活动是否开始了
        if( !redisTemplate.hasKey(productRedisKey) ){
            logger.info("当前活动并未开始");
            return false;
        }

        // 5.判断当前是否参加了秒杀了
        if( redisTemplate.opsForSet().isMember(userRedisKey,userId) ){
            logger.info("当前用户已经参加了秒杀活动了");
            return false;
        }

        // 6.如果商品数量 <1了那么，秒杀活动结束了
        int productNum = Integer.parseInt((String)redisTemplate.opsForValue().get(productRedisKey));
        if( productNum <= 0 ){
            logger.info("秒杀活动已经结束了");
            return false;
        }

        // 7.秒杀活动逻辑
        redisTemplate.opsForValue().decrement(productRedisKey);
        redisTemplate.opsForSet().add(userRedisKey,userId);
        logger.info("秒杀成功");
        return true;
    }


}
